﻿Public Class Document

	Dim Report As New Report
	Dim WithEvents PD As New PrintDocument
	Dim VirtualHeight As Integer
	Dim PageSize As New Size
	Dim MarginBounds As New Size
	Shadows Layout As Layout

	Property Landscape As Boolean
		Get
			Return PD.DefaultPageSettings.Landscape
		End Get
		Set(Value As Boolean)
			PD.DefaultPageSettings.Landscape = Value
			PD.DefaultPageSettings.Margins = New Margins(75, 75, 75, 75)
			PageSize = PD.DefaultPageSettings.Bounds.Size
			MarginBounds = PageSize
			MarginBounds.Width -= PD.DefaultPageSettings.Margins.Left + PD.DefaultPageSettings.Margins.Right
			MarginBounds.Height -= PD.DefaultPageSettings.Margins.Top + PD.DefaultPageSettings.Margins.Bottom
		End Set
	End Property

	Sub New()
		Landscape = False
		InitializeComponent()
	End Sub

	Dim _Zoom As Integer = 1
	Property Zoom As Integer
		Get
			Return _Zoom
		End Get
		Set(Value As Integer)
			_Zoom = Value
			Recalculate()
		End Set
	End Property

	ReadOnly Property ZoomFactor As Single
		Get
			Select Case Zoom
				Case 1 : Return (Picture.Width - 20) / MarginBounds.Width
				Case 2 : Return Picture.Width / PageSize.Width
				Case 3 : Return Picture.Height / PageSize.Height
			End Select
			Return 1
		End Get
	End Property

	ReadOnly Property MarginWidth As Single
		Get
			Return PageSize.Width - MarginBounds.Width
		End Get
	End Property

	ReadOnly Property MarginHeight As Single
		Get
			Return PageSize.Height - MarginBounds.Height
		End Get
	End Property

	Property HasBorders As Boolean

	Sub Recalculate()
		If MarginBounds.IsEmpty Then Exit Sub
		VirtualHeight = PageSize.Height * ZoomFactor
		ScrollBar.Maximum = VirtualHeight - Choose(Zoom, ZoomFactor * (MarginHeight - 20), 0, 0)
		ScrollBar.Enabled = ScrollBar.Maximum > Picture.Height
		ScrollBar.SmallChange = Picture.Width / 10
		If ScrollBar.Maximum >= ScrollBar.LargeChange AndAlso ScrollBar.Value > ScrollBar.Maximum - ScrollBar.LargeChange Then ScrollBar.Value = ScrollBar.Maximum - ScrollBar.LargeChange
		If ScrollBar.Enabled Then ScrollBar.LargeChange = Picture.Height
		ScrollBar.Minimum = 0 ' Choose(Zoom, ZoomFactor * PD.DefaultPageSettings.Margins.Top, 0, 0)
		If Not ScrollBar.Enabled Then ScrollBar.Value = ScrollBar.Minimum
		Picture.Invalidate()
	End Sub

	Private Sub Picture_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
		Dim nw = ScrollBar.Value - e.Delta / 100 * ScrollBar.SmallChange
		If nw < ScrollBar.Minimum Then nw = ScrollBar.Minimum
		If nw > ScrollBar.Maximum - ScrollBar.LargeChange Then nw = ScrollBar.Maximum - ScrollBar.LargeChange
		ScrollBar.Value = nw
	End Sub

	Property EmptyMessage As String

	Private Sub Picture_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Picture.Paint
		e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
		e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
		e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
		e.Graphics.Clear(Color.White)
		If Layout Is Nothing Then
			e.Graphics.DrawString(EmptyMessage, New Font("arial", 16, FontStyle.Regular), Brushes.Gray, 16, 16)
			Return
		End If
		e.Graphics.ScaleTransform(ZoomFactor, ZoomFactor)
		e.Graphics.TranslateTransform(Choose(Zoom, 10, PD.DefaultPageSettings.Margins.Left, 0), -ScrollBar.Value / ZoomFactor + Choose(Zoom, 10, PD.DefaultPageSettings.Margins.Top, 0))
		Layout.Paint(e.Graphics, Page - 1)
		'e.Graphics.DrawRectangle(Pens.Red, New Rectangle(0, 0, MarginBounds.Width, MarginBounds.Height))
	End Sub

	Private Sub Picture_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Picture.Resize
		Recalculate()
		Picture.Invalidate()
	End Sub

	Dim Section As Report.Section
	Sub AddSection()
		Section = Report.AddSection()
	End Sub

	Dim Table As Report.Table
	Function AddTable(ByVal p1 As String) As Document
		Table = Section.Body.AddTable(p1)
		Table.HasBorders = Me.HasBorders
		Return Me
	End Function

	Sub AddHeader(ByVal ParamArray Values() As Object)
		Table.AddHeader(Values)
	End Sub

	Function Skip(Optional Count As Integer = 1) As Document
		For i = 1 To Count
			AddRow(" ")
		Next
		Return Me
	End Function

	<DebuggerHidden()>
	Function AddRow(ByVal ParamArray Values() As Object) As Document
		Table.AddRow(Values)
		Return Me
	End Function

	Sub Display()
		Layout = New Layout
		Layout.Width = MarginBounds.Width
		Layout.Height = MarginBounds.Height
		Dim B As New Bitmap(1, 1)
		Layout.Graphics = Graphics.FromImage(B)
		Report.Prepare(Layout)
		Recalculate()
		GotoPage(1)
	End Sub

	Sub Display(HTMLText As String)
		HTML.Parse(HTMLText)
		Display()
	End Sub

	Private Sub ScrollBar_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ScrollBar.ValueChanged
		Dim nw = ScrollBar.Value
		If nw > ScrollBar.Maximum - ScrollBar.LargeChange Then nw = ScrollBar.Maximum - ScrollBar.LargeChange
		ScrollBar.Value = nw
		Picture.Invalidate()
	End Sub

	Sub Clear()
		Report.Clear()
	End Sub

	Dim PrintingPage As Integer = 0

	Private Sub BtnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnPrint.Click
		PD.OriginAtMargins = True
		PrintingPage = 0
		PD.Print()
	End Sub

	Private Sub PD_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PD.PrintPage
		Layout.Paint(e.Graphics, PrintingPage)
		PrintingPage += 1
		e.HasMorePages = PrintingPage < Layout.Pages.Count
	End Sub

	Sub AddTitle(ByVal Title As String)
		Title = Title.Replace("/n", vbCrLf)
		With Report.Sections.Last.Header.AddTable("1")
			.AddRow(Title)
		End With
	End Sub

	Dim Page As Integer
	Private Sub GotoPage(ByVal Page As Integer)
		Me.Page = Page
		BtnFirst.Enabled = Page > 1
		BtnPrev.Enabled = Page > 1
		BtnNext.Enabled = Page < Layout.Pages.Count
		BtnLast.Enabled = Page < Layout.Pages.Count
		Picture.Invalidate()
	End Sub

	Private Sub ToolBar_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ToolBar.ItemClicked
		If e.ClickedItem Is BtnFirst Then
			GotoPage(1)
		ElseIf e.ClickedItem Is BtnPrev Then
			GotoPage(Page - 1)
		ElseIf e.ClickedItem Is BtnNext Then
			GotoPage(Page + 1)
		ElseIf e.ClickedItem Is BtnLast Then
			GotoPage(Layout.Pages.Count)
		End If
	End Sub

	Private Sub MnuZoom_Click(sender As System.Object, e As System.EventArgs) Handles MnuZoom2.Click, MnuZoom1.Click, MnuZoom3.Click
		Zoom = Strings.Right(sender.Name, 1)
	End Sub

End Class

Public Class Layout

	Public y As Integer = 0
	Public Graphics As Graphics
	Public Width As Integer
	Public Height As Integer

	Public Pages As New List(Of Page)

	Sub AddPage()
		Pages.Add(New Page)
		y = 0
	End Sub

	Class Page

		Public Items As New List(Of PrintItem)

		Sub Paint(ByVal g As Graphics)
			For Each Item In Items
				Item.Paint(g)
			Next
		End Sub

	End Class

	Class PrintItem
		Public Rect As Rectangle
		Public Text As String
		Public Font As Font
		Public Align As String = "center"
		Public HasBorders As Boolean

		Sub Paint(ByVal g As Drawing.Graphics)
			If HasBorders Then g.DrawRectangle(Pens.Gray, Rect)
			Dim F As New StringFormat
			F.LineAlignment = StringAlignment.Center
			If Align = "right" Then F.Alignment = StringAlignment.Far
			If Align = "center" Then F.Alignment = StringAlignment.Center
			g.DrawString(Text, Font, Brushes.Black, Rect, F)
		End Sub

	End Class

	Function CheckPageLimits(ByVal LineHeight As Integer) As Boolean
		If y + LineHeight <= Height Then Return True
		AddPage()
		Return False
	End Function

	Sub AddItem(ByVal Item As PrintItem)
		Pages.Last.Items.Add(Item)
	End Sub

	Sub Paint(ByVal g As Drawing.Graphics, ByVal PageNo As Integer)
		If Pages.Count <= PageNo Then Exit Sub
		Pages(PageNo).Paint(g)
	End Sub

	Sub Clear()
		Pages.Clear()
		AddPage()
	End Sub

End Class

